package com.testpro.EasyUseCase.Core.Abstract;

import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.metadata.BaseRowModel;
import com.testpro.EasyUseCase.Core.Interface.Convert;
import com.testpro.easyrest.Util.ExcelUtil;
import java.io.FileInputStream;
import lombok.extern.slf4j.Slf4j;
import org.xmind.core.*;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

@Slf4j
public abstract class AbstractConvert<T extends BaseRowModel> implements Convert {

  public ITopic getRootTopic() {
    return RootTopic;
  }

  public void setRootTopic(ITopic rootTopic) {
    RootTopic = rootTopic;
  }

  private ITopic RootTopic;
  private Class<T> tClass;

  public String getInputXMindFilePath() {
    return InputXMindFilePath;
  }

  public String getOutPutExcelFilePath() {
    return OutPutExcelFilePath;
  }

  private String InputXMindFilePath;
  private String OutPutExcelFilePath;
  public AbstractConvert() {
            tClass = (Class<T>) getModelClass( 0);
    log.info("泛型类构造方法获取到了泛型参数具体类型" + this.getClass().getSimpleName() + "[" + tClass.getSimpleName()+ "]");
  }

  public void Convert() {
    this.initConfig();
    File file = this.getFile();
    LinkedList<ITopic> iTopicList = this.getITopicList(file);
    LinkedList<T> analysis = this.analysis(iTopicList);
    this.writeExcel(analysis, tClass);
  }

  private void initConfig() {
    log.info("读取配置文件application.properties");
    if (OutPutExcelFilePath != null && InputXMindFilePath != null) {
      log.info(OutPutExcelFilePath);
      log.info(InputXMindFilePath);
      return;
    } else if (InputXMindFilePath != null) {
      OutPutExcelFilePath = "C://output.xlsx";
      return;
    }
    ClassPathResource resource = new ClassPathResource("application.properties");
    try {
      Properties properties = new Properties();
      InputStreamReader inputStreamReader = new InputStreamReader(resource.getStream(), "GBK");
      properties.load(inputStreamReader);
      if (!properties.isEmpty()) {
        for (String key : properties.stringPropertyNames()) {
          if (key.equals("easyusecase.inputxmind.filepath")) {
            this.InputXMindFilePath = properties.getProperty(key);
            System.setProperty(key, properties.getProperty(key));
          }
          if (key.equals("easyusecase.outputExcel.filepath")) {
            this.OutPutExcelFilePath = properties.getProperty(key);
            System.setProperty(key, properties.getProperty(key));
          }
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
      throw new RuntimeException("找不到配置文件");
    }
  }

  private File getFile() {
    if (!StrUtil.isEmpty(InputXMindFilePath)) {
      File file = new File(InputXMindFilePath);
      return file;
    } else {
      throw new RuntimeException("文件地址不正确或找不到文件");
    }
  }

  private LinkedList<ITopic> getITopicList(File file) {
    IWorkbookBuilder builder = Core.getWorkbookBuilder();
    IWorkbook iWorkbook = null;
    try {
      iWorkbook = builder.loadFromStream(new FileInputStream(file),".");
    } catch (IOException | CoreException e) {
      e.printStackTrace();
    }
    assert iWorkbook != null;
    ISheet primarySheet = iWorkbook.getPrimarySheet();
    ITopic rootTopic = primarySheet.getRootTopic();
    setRootTopic(rootTopic);
    LinkedList<ITopic> linkedITopicList = new LinkedList<ITopic>();
    reITopic(rootTopic, linkedITopicList);

    return linkedITopicList;
  }

  private void reITopic(ITopic rootTopic, LinkedList<ITopic> linkedITopicList) {
    List<ITopic> allChildren = rootTopic.getAllChildren();
    if (allChildren.size() == 0) {
      linkedITopicList.add(rootTopic);
    } else {
      for (ITopic topic : allChildren) {
        reITopic(topic, linkedITopicList);
      }
    }
  }

  private void writeExcel(LinkedList<T> listUseCase, Class<T> tClass) {
    {
      try {
        System.out.println(OutPutExcelFilePath);
        new ExcelUtil().WriterExcelWithListBean(new File(OutPutExcelFilePath), listUseCase, tClass);
        writeExcelDG(listUseCase, OutPutExcelFilePath, tClass);
      } catch (IOException e) {
        throw new RuntimeException("目标文件被打开 无法执行写入操作请关闭目标文件" + OutPutExcelFilePath);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  protected abstract void writeExcelDG(
      LinkedList<T> listUseCase, String outPutExcelFilePath, Class<T> tClass)
      throws FileNotFoundException;

  private Class<?> getModelClass(int index) {
    // 得到泛型父类

    Type genType = this.getClass().getGenericSuperclass();
    // 一个泛型类可能有多个泛型形参，比如ClassName<T,K> 这里有两个泛型形参T和K，Class Name<T> 这里只有1个泛型形参T
    Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
    if (params.length - 1 < index) {
      return null;
    } else {
     return  (Class) params[index];
    }
  }

  public void setInputXMindFilePath(String inputXMindFilePath) {
    this.InputXMindFilePath = inputXMindFilePath;
  }

  public void setOutPutExcelFilePath(String outPutExcelFilePath) {
    this.OutPutExcelFilePath = outPutExcelFilePath;
  }

  /**
   * 参数是全部脑图的对象 要求你自定义分析出来你想要的对象格式T必须继承BaseRowModel类 可以参考XmindUseCase
   *
   * @param linkedITopicList
   * @return 你想要的对象格式T必须继承BaseRowModel类
   */
  protected abstract LinkedList<T> analysis(LinkedList<ITopic> linkedITopicList);
}
